package com.wyz.demo.core.infrastructure.config;

import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.wyz.demo.common.constant.Knife4jConstant;
import com.wyz.demo.core.infrastructure.utils.PackageUtil;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.CollectionUtils;
import springfox.documentation.RequestHandler;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;

import java.util.Set;
import java.util.stream.Collectors;

/**
 * @Description: Knife4j api配置文档
 * @Author: wei yz
 * @Date: 2022/7/9
 */
@Configuration
@EnableSwagger2WebMvc
public class Knife4jConfiguration {

    /**
     * 定义分隔符,配置Swagger多包
     */
    private static final String SPLITOR = ";";

    @Bean(value = "defaultApi2")
    public Docket defaultApi2() {
        Docket docket = new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(new ApiInfoBuilder()
                        .title(Knife4jConstant.TITLE)
                        .description(Knife4jConstant.DESC)
                        .termsOfServiceUrl(Knife4jConstant.URL)
                        .contact(Knife4jConstant.CONTACT)
                        .version(Knife4jConstant.VERSION)
                        .build())
                //分组名称
                .groupName(Knife4jConstant.GROUP_NAME)
                .select()
                //这里指定Controller扫描包路径
                .apis(basePackage(splicePath(Knife4jConstant.APIS_PATH, Knife4jConstant.LAST_INDEX_STR)))
                .paths(PathSelectors.any())
                .build();
        return docket;
    }

    private static String splicePath(String basePath, String lastIndexStr) {
        // 获取所有子包名
        Set<String> pakSets = PackageUtil.getPackageChild(basePath, lastIndexStr);
        if (!CollectionUtils.isEmpty(pakSets)) {
            // 拼接;组成字符串
            return pakSets.stream().collect(Collectors.joining(SPLITOR));
        }
        return "";
    }

    public static Predicate<RequestHandler> basePackage(final String basePackage) {
        return input -> declaringClass(input).transform(handlerPackage(basePackage)).or(true);
    }

    private static Function<Class<?>, Boolean> handlerPackage(final String basePackage) {
        return input -> {
            // 循环判断匹配
            for (String strPackage : basePackage.split(SPLITOR)) {
                boolean isMatch = input.getPackage().getName().startsWith(strPackage);
                if (isMatch) {
                    return true;
                }
            }
            return false;
        };
    }

    private static Optional<? extends Class<?>> declaringClass(RequestHandler input) {
        return Optional.fromNullable(input.declaringClass());
    }

}
